﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace GTA
{
    public partial class FrmUserManagement : BaseForm
    {
        #region Local Objects
        private BusinessEntity.UserManagement.User userEdit = null;
        private List<BusinessEntity.UserManagement.User> listUsers;
        private List<BusinessEntity.UserManagement.UserAbsences> listAbsences;
        private List<DateTime> listAdditionalDays;
        #endregion

        #region Starting Form
        public FrmUserManagement()
        {
            InitializeComponent();
        }
        private void FrmUserManagement_Load(object sender, EventArgs e)
        {
            StartForm();
        }
        private void StartForm()
        {
            try
            {
                LoadCurrentUsers();
                LoadProjects();
                LoadGroups();
            }
            catch (Exception ex)
            {
                HandleException("Inicialização da Tela", ex);
            }
        }
        #endregion

        #region Events
        private void cmdSave_Click(object sender, EventArgs e)
        {
            SaveUser();
        }
        private void cmsClean_Click(object sender, EventArgs e)
        {
            CleanForm();
        }
        private void cmdEdit_Click(object sender, EventArgs e)
        {
            EditSelectedUser();
        }
        private void cmdDelete_Click(object sender, EventArgs e)
        {
            DeleteSelectedUsers();
        }
        private void editarToolStripMenuItem_Click(object sender, EventArgs e)
        {
            EditSelectedUser();
        }
        private void excluirToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DeleteSelectedUsers();
        }
        private void lstUsers_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Delete)
                DeleteSelectedUsers();
        }
        private void lstUsers_DoubleClick(object sender, EventArgs e)
        {
            EditSelectedUser();
        }
        private void lstUsers_ColumnClick(object sender, ColumnClickEventArgs e)
        {
            SortList(lstUsers, GetColumnTypeLstUsers(e.Column), ref columnOrder, ref sortOrder, e.Column);
        }
        private void lstUserAbsences_ColumnClick(object sender, ColumnClickEventArgs e)
        {
            SortList(lstUserAbsences, GetColumnTypeLstUserAbsences(e.Column), ref columnOrder, ref sortOrder, e.Column);
        }
        private void lstUserAdditionalDays_ColumnClick(object sender, ColumnClickEventArgs e)
        {
            SortList(lstUserAdditionalDays, GetColumnTypeLstUserAdditionalDays(e.Column), ref columnOrder, ref sortOrder, e.Column);
        }
        private void cmdIncludeAbsence_Click(object sender, EventArgs e)
        {
            IncludeUserAbsence();
        }
        private void cmdRemoveAbsence_Click(object sender, EventArgs e)
        {
            RemoveUserAbsence();
        }
        private void cmdIncludeAdditionalDay_Click(object sender, EventArgs e)
        {
            IncludeUserAdditionalDay();
        }
        private void cmdRemoveAdditionalDay_Click(object sender, EventArgs e)
        {
            RemoveUserAdditionalDay();
        }
        private void lstProjects_ItemChecked(object sender, ItemCheckedEventArgs e)
        {
            if (e.Item.Equals(lstProjects.Items[0]))
            {
                foreach (ListViewItem item in lstProjects.Items)
                    item.Checked = lstProjects.Items[0].Checked;
            }
        }
        private void txtLogin_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar.CompareTo(' ') == 0)
                e.Handled = true;
        }
        private void lstUsers_Resize(object sender, EventArgs e)
        {
            lstUsers.Columns[1].Width = lstUsers.Size.Width - lstUsers.Columns[0].Width - lstUsers.Columns[2].Width - lstUsers.Columns[3].Width - lstUsers.Columns[4].Width - 23;
        }
        private void lstUserAdditionalDays_Resize(object sender, EventArgs e)
        {
            lstUserAdditionalDays.Columns[0].Width = lstUserAdditionalDays.Width - 20;
        }
        private void lstUserAbsences_Resize(object sender, EventArgs e)
        {
            lstUserAbsences.Columns[0].Width = ((lstUserAbsences.Width - lstUserAbsences.Columns[2].Width) / 2) - 10;
            lstUserAbsences.Columns[1].Width = ((lstUserAbsences.Width - lstUserAbsences.Columns[2].Width) / 2) - 10;
        }
        #endregion

        #region Methods
        private void LoadCurrentUsers()
        {
            try
            {
                BusinessLogic.GTA bl = new BusinessLogic.GTA();
                listUsers = bl.ListUsers(new GTA.BusinessEntity.UserManagement.UserFilter());
                lstUsers.Items.Clear();
                if (listUsers != null && listUsers.Count > 0)
                {
                    foreach (BusinessEntity.UserManagement.User itemUser in listUsers)
                    {
                        ListViewItem listItem = new ListViewItem(itemUser.ID.ToString());
                        listItem.SubItems.Add(itemUser.Name);
                        listItem.SubItems.Add(itemUser.Login);
                        listItem.SubItems.Add(itemUser.UserProfile.Description);
                        listItem.SubItems.Add(itemUser.UserGroup.Name);
                        lstUsers.Items.Add(listItem);
                    }
                }
            }
            catch (Exception ex)
            {
                HandleException("Carregar a lista de usuários atuais.", ex);
            }
        }
        private void LoadProjects()
        {
            try
            {
                BusinessLogic.GTA bl = new BusinessLogic.GTA();
                lstProjects.Items.Add("Todos");
                if (Program.Projects != null)
                    Program.Projects.ForEach(item => lstProjects.Items.Add(item.Name));
            }
            catch (Exception ex)
            {
                HandleException("Carregar a lista de projetos", ex);
            }
        }
        private void LoadGroups()
        {
            try
            {
                BusinessLogic.GTA bl = new BusinessLogic.GTA();
                List<BusinessEntity.Group> groups = bl.ListGroups();
                if (groups == null)
                    groups = new List<GTA.BusinessEntity.Group>();
                groups.Insert(0, new GTA.BusinessEntity.Group() { ID = 0, Name = "Selecione..." });
                cmbGroups.ValueMember = "ID";
                cmbGroups.DisplayMember = "Name";
                cmbGroups.DataSource = groups;
            }
            catch (Exception ex)
            {
                HandleException("Carregar a lista de grupos", ex);
            }
        }
        private void LoadAbsences()
        {
            try
            {
                lstUserAbsences.Items.Clear();
                if (listAbsences != null && listAbsences.Count > 0)
                {
                    foreach (BusinessEntity.UserManagement.UserAbsences itemAbsence in listAbsences)
                    {
                        ListViewItem listItem = new ListViewItem(itemAbsence.StartDate.ToString(DATE_FORMAT));
                        listItem.SubItems.Add(itemAbsence.EndDate.ToString(DATE_FORMAT));
                        listItem.SubItems.Add(itemAbsence.WeekEnd ? "Sim" : "Não");
                        lstUserAbsences.Items.Add(listItem);
                    }
                }
            }
            catch (Exception ex)
            {
                HandleException("Carregar a lista de folgas", ex);
            }
        }
        private void LoadAdditionalDays()
        {
            try
            {
                lstUserAdditionalDays.Items.Clear();
                if (listAdditionalDays != null && listAdditionalDays.Count > 0)
                {
                    foreach (DateTime itemAdditionalDay in listAdditionalDays)
                    {
                        ListViewItem listItem = new ListViewItem(itemAdditionalDay.ToString(DATE_FORMAT));
                        lstUserAdditionalDays.Items.Add(listItem);
                    }
                }
            }
            catch (Exception ex)
            {
                HandleException("Carregar a lista de dias adicionais.", ex);
            }
        }
        private void SaveUser()
        {
            try
            {
                if (ValidateForm())
                {
                    BusinessEntity.UserManagement.User user = GetUserData();
                    BusinessLogic.GTA bl = new BusinessLogic.GTA();
                    bl.SaveUser(user);
                    MessageBox.Show("Dados salvos com sucesso!", "Confirmação", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    CleanForm();
                    LoadCurrentUsers();
                }
            }
            catch (Exception ex)
            {
                HandleException("Salvar novo usuário.", ex);
            }
        }
        private bool ValidateForm()
        {
            bool valid = true;
            StringBuilder message = new StringBuilder("Informe os campos obrigatórios:\r\n");
            if (String.IsNullOrEmpty(txtName.Text))
            {
                valid = false;
                message.Append("\r\nNome do usuário");
            }
            if (String.IsNullOrEmpty(txtLogin.Text))
            {
                valid = false;
                message.Append("\r\nLogin do usuário");
            }
            if (String.IsNullOrEmpty(txtPassword.Text))
            {
                valid = false;
                message.Append("\r\nSenha do usuário");
            }
            if (cmbGroups.SelectedIndex <= 0)
            {
                valid = false;
                message.Append("\r\nGrupo do Usuário");
            }
            if (lstProjects.CheckedItems.Count == 0)
            {
                valid = false;
                message.Append("\r\nSelecione ao menos um projeto para o usuário");
            }
            if (!valid)
                MessageBox.Show(message.ToString(), "Alerta", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            return valid;
        }
        private BusinessEntity.UserManagement.User GetUserData()
        {
            BusinessEntity.UserManagement.User user = new GTA.BusinessEntity.UserManagement.User();
            if (userEdit != null)
                user.ID = userEdit.ID;
            user.Name = txtName.Text.Trim();
            user.Login = txtLogin.Text.Trim();
            user.Password = GTA.Cryptography.Util.DESCryptographer.Encrypt(txtPassword.Text.Trim());
            user.EMailAddress = txtUserEMail.Text.Trim();
            user.UserGroup = cmbGroups.SelectedItem as BusinessEntity.Group;
            if (opProfilerMaster.Checked)
                user.UserProfile = BusinessEntity.UserManagement.Profiler.Master;
            else if (opAdministrator.Checked)
                user.UserProfile = BusinessEntity.UserManagement.Profiler.External;
            else if (opProfilerUser.Checked)
                user.UserProfile = BusinessEntity.UserManagement.Profiler.User;
            user.UserAbsences = listAbsences;
            user.UserAdditionalDays = listAdditionalDays;
            user.UserProjects = GetSelectedProjects();
            return user;
        }
        private List<BusinessEntity.Project> GetSelectedProjects()
        {
            List<BusinessEntity.Project> projects = new List<GTA.BusinessEntity.Project>();
            foreach (ListViewItem listItem in lstProjects.CheckedItems)
            {
                if (!listItem.Equals(lstProjects.Items[0]))
                    projects.Add(new GTA.BusinessEntity.Project() { Name = listItem.Text });
            }
            return projects;
        }
        private void CleanForm()
        {
            txtName.Text = String.Empty;
            txtLogin.Text = String.Empty;
            txtLogin.Enabled = true;
            txtPassword.Text = String.Empty;
            txtPassword.Enabled = true;
            txtUserEMail.Text = String.Empty;
            opProfilerUser.Checked = true;
            cmbGroups.SelectedIndex = cmbGroups.Items.Count > 0 ? 0 : -1;
            foreach (ListViewItem item in lstProjects.Items)
                item.Checked = false;
            lstProjects.Items[0].Selected = true;
            txtName.Focus();
            userEdit = null;
            listAbsences = null;
            listAdditionalDays = null;
            LoadAbsences();
            LoadAdditionalDays();
        }
        private void EditSelectedUser()
        {
            try
            {
                if (lstUsers.SelectedItems.Count == 1)
                {
                    BusinessEntity.UserManagement.User user = listUsers.Find(it => it.ID.CompareTo(Convert.ToInt32(lstUsers.SelectedItems[0].SubItems[0].Text)) == 0);
                    if (user != null)
                    {
                        txtName.Text = user.Name;
                        txtLogin.Text = user.Login;
                        txtPassword.Text = GTA.Cryptography.Util.DESCryptographer.Decrypt(user.Password);
                        if (user.UserProfile == BusinessEntity.UserManagement.Profiler.Master)
                            opProfilerMaster.Checked = true;
                        else if (user.UserProfile == BusinessEntity.UserManagement.Profiler.External)
                            opAdministrator.Checked = true;
                        else if (user.UserProfile == BusinessEntity.UserManagement.Profiler.User)
                            opProfilerUser.Checked = true;
                        txtUserEMail.Text = user.EMailAddress;
                        cmbGroups.SelectedValue = user.UserGroup.ID;
                        foreach (BusinessEntity.Project itemProject in user.UserProjects)
                        {
                            foreach (ListViewItem listItem in lstProjects.Items)
                            {
                                if (listItem.Text.CompareTo(itemProject.Name) == 0)
                                {
                                    listItem.Checked = true;
                                    break;
                                }
                            }
                        }
                        listAbsences = user.UserAbsences;
                        listAdditionalDays = user.UserAdditionalDays;
                        LoadAbsences();
                        LoadAdditionalDays();
                        userEdit = user;
                        txtName.Focus();

                        txtPassword.Enabled = Program.LoggedUser != null && user.ID.CompareTo(Program.LoggedUser.ID) == 0;
                        txtLogin.Enabled = Program.LoggedUser != null && user.ID.CompareTo(Program.LoggedUser.ID) == 0;
                    }
                }
                else
                    MessageBox.Show("Selecione apenas um usuário para editar", "Alerta", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
            catch (Exception ex)
            {
                HandleException("Editar um usuário.", ex);
            }
        }
        private void DeleteSelectedUsers()
        {
            try
            {
                if (lstUsers.SelectedItems.Count > 0)
                {
                    if (MessageBox.Show("Deseja realmente excluir os usuários selecionados?\r\nEsta ação não pode ser desfeita e todas as configurações do usuário também serão excluídas!\r\n\r\nContinuar?", "Questão", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
                    {
                        BusinessLogic.GTA bl = new BusinessLogic.GTA();
                        while (lstUsers.SelectedItems.Count > 0)
                        {
                            bl.DeleteUser(Convert.ToInt32(lstUsers.SelectedItems[0].SubItems[0].Text));
                            lstUsers.SelectedItems[0].Remove();
                        }
                        MessageBox.Show("Usuários excluídos com sucesso!", "Confirmação", MessageBoxButtons.OK, MessageBoxIcon.Information);
                        LoadCurrentUsers();
                    }
                }
                else
                    MessageBox.Show("Selecione ao menos um usuário para excluir", "Alerta", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
            catch (Exception ex)
            {
                HandleException("Excluir usuários selecionados.", ex);
            }
        }
        private void IncludeUserAbsence()
        {
            try
            {
                if (ValidateAbsenceInterval())
                {
                    if (listAbsences == null)
                        listAbsences = new List<GTA.BusinessEntity.UserManagement.UserAbsences>();
                    listAbsences.Add(new GTA.BusinessEntity.UserManagement.UserAbsences()
                    {
                        StartDate = txtStartDateAbsence.Value,
                        EndDate = txtEndDateAbsence.Value,
                        WeekEnd = ckIncludeWeekendAbscence.Checked
                    });
                    LoadAbsences();
                }
            }
            catch (Exception ex)
            {
                HandleException("Incluir folgas para o usuário.", ex);
            }
        }
        private bool ValidateAbsenceInterval()
        {
            bool valid = true;

            if (txtStartDateAbsence.Value.Date.CompareTo(txtEndDateAbsence.Value.Date) > 0)
            {
                valid = false;
                MessageBox.Show("A Data Final não pode ser maior que a Data Inicial!", "Alerta", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }

            if (valid)
            {
                if (listAbsences != null && listAbsences.Count > 0)
                    valid = listAbsences.Find(it =>
                        (txtStartDateAbsence.Value.Date.CompareTo(it.StartDate.Date) >= 0 &&
                        txtEndDateAbsence.Value.Date.CompareTo(it.EndDate.Date) <= 0) ||
                        (txtStartDateAbsence.Value.Date.CompareTo(it.StartDate.Date) <= 0 &&
                        txtEndDateAbsence.Value.Date.CompareTo(it.StartDate.Date) > 0) ||
                        (txtStartDateAbsence.Value.Date.CompareTo(it.EndDate.Date) <= 0 &&
                        txtEndDateAbsence.Value.Date.CompareTo(it.EndDate.Date) > 0)) == null;
            }

            if (!valid)
                MessageBox.Show("O intervalo informado está em intersecção com os intervalos existentes!", "Alerta", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);

            return valid;
        }
        private void RemoveUserAbsence()
        {
            try
            {
                if (lstUserAbsences.SelectedItems.Count > 0)
                {
                    for (int i = 0; i < lstUserAbsences.SelectedItems.Count; i++)
                    {
                        if (listAbsences.Remove(listAbsences.Find(it =>
                            it.StartDate.Date.CompareTo(Convert.ToDateTime(lstUserAbsences.SelectedItems[i].SubItems[0].Text).Date) == 0 &&
                            it.EndDate.Date.CompareTo(Convert.ToDateTime(lstUserAbsences.SelectedItems[i].SubItems[1].Text).Date) == 0)))
                        {
                            lstUserAbsences.SelectedItems[i].Remove();
                            i--;
                        }
                    }
                }
                else
                    MessageBox.Show("Selecione ao menos um intervalo para excluir!", "Alerta", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
            catch (Exception ex)
            {
                HandleException("Remover folgas do usuário.", ex);
            }
        }
        private void IncludeUserAdditionalDay()
        {
            try
            {
                if (ValidateExistingAdditionalDate())
                {
                    if (listAdditionalDays == null)
                        listAdditionalDays = new List<DateTime>();
                    listAdditionalDays.Add(txtDateAdditionalDay.Value);
                    LoadAdditionalDays();
                }
            }
            catch (Exception ex)
            {
                HandleException("Incluir dias adicionais de trabalho para o usuário.", ex);
            }
        }
        private bool ValidateExistingAdditionalDate()
        {
            bool valid = true;
            if (listAdditionalDays != null && listAdditionalDays.Count > 0)
                valid = listAdditionalDays.Find(it => it.Date.CompareTo(txtDateAdditionalDay.Value.Date) == 0) == DateTime.MinValue;
            if (!valid)
                MessageBox.Show("Já existe esta data, informe uma data diferente!", "Alerta", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            return valid;
        }
        private void RemoveUserAdditionalDay()
        {
            try
            {
                if (lstUserAdditionalDays.SelectedItems.Count > 0)
                {
                    for (int i = 0; i < lstUserAdditionalDays.SelectedItems.Count; i++)
                    {
                        if (listAdditionalDays.Remove(listAdditionalDays.Find(it =>
                            it.Date.CompareTo(Convert.ToDateTime(lstUserAdditionalDays.SelectedItems[i].SubItems[0].Text).Date) == 0)))
                        {
                            lstUserAdditionalDays.SelectedItems[i].Remove();
                            i--;
                        }
                    }
                }
                else
                    MessageBox.Show("Selecione ao menos um intervalo para excluir!", "Alerta", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
            catch (Exception ex)
            {
                HandleException("Remover dias adicinoais de trabalho do usuário.", ex);
            }
        }
        private OrdenacaoListView.Tipo GetColumnTypeLstUsers(Int32 column)
        {
            switch (column)
            {
                case 0:
                    return OrdenacaoListView.Tipo.Numerica;
                case 1:
                    return OrdenacaoListView.Tipo.Alfabetica;
                case 2:
                    return OrdenacaoListView.Tipo.Alfabetica;
                case 3:
                    return OrdenacaoListView.Tipo.Alfabetica;
                default:
                    return OrdenacaoListView.Tipo.Alfabetica;
            }
        }
        private OrdenacaoListView.Tipo GetColumnTypeLstUserAbsences(Int32 column)
        {
            switch (column)
            {
                case 0:
                    return OrdenacaoListView.Tipo.Data;
                case 1:
                    return OrdenacaoListView.Tipo.Data;
                case 2:
                    return OrdenacaoListView.Tipo.Alfabetica;
                default:
                    return OrdenacaoListView.Tipo.Alfabetica;
            }
        }
        private OrdenacaoListView.Tipo GetColumnTypeLstUserAdditionalDays(Int32 column)
        {
            switch (column)
            {
                case 0:
                    return OrdenacaoListView.Tipo.Data;
                default:
                    return OrdenacaoListView.Tipo.Alfabetica;
            }
        }
        #endregion
    }
}
